﻿using System;
using System.Linq;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Mbox2Eml.Properties;

namespace Mbox2Eml
{
    public partial class MainForm : Form
    {
        private ETACalculator ETACalculator;

        public MainForm()
        {
            InitializeComponent();
        }

        #region Save / Load
        private void MainForm_Load(object sender, EventArgs e)
        {
            txtMboxFolder.Text = Settings.Default.MbxFolder;
            txtOutputFolder.Text = Settings.Default.OutputFolder;
        }

        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            Settings.Default.MbxFolder = txtMboxFolder.Text;
            Settings.Default.OutputFolder = txtOutputFolder.Text;

            Settings.Default.Save();
        }
        #endregion

        private void btnSelectMboxFolder_Click(object sender, EventArgs e)
        {
            if (DialogResult.OK == folderBrowserDialogMbox.ShowDialog())
            {
                txtMboxFolder.Text = folderBrowserDialogMbox.SelectedPath;
            }
        }

        private void btnSelectoutputFolder_Click(object sender, EventArgs e)
        {
            if (DialogResult.OK == folderBrowserDialogOutput.ShowDialog())
            {
                txtOutputFolder.Text = folderBrowserDialogOutput.SelectedPath;
            }
        }

        private void BeginBlock()
        {
            Cursor = Cursors.WaitCursor;
            btnSelectMboxFolder.Enabled = false;
            btnSelectOutputFolder.Enabled = false;
        }

        private void EndBlock()
        {
            Cursor = Cursors.Default;
            btnSelectMboxFolder.Enabled = true;
            btnSelectOutputFolder.Enabled = true;
        }

        private void btnConvert_Click(object sender, EventArgs e)
        {
            string mboxfolder = txtMboxFolder.Text;
            string outputfolder = txtOutputFolder.Text;

            if (!string.IsNullOrWhiteSpace(mboxfolder) && !string.IsNullOrWhiteSpace(outputfolder))
            {
                if (mboxfolder == outputfolder)
                {
                    MessageBox.Show("'Local Mbox Folder' and 'Output Folder' are the same.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }

                if (backgroundWorker.IsBusy)
                {
                    backgroundWorker.CancelAsync();
                }
                else
                {
                    BeginBlock();

                    lblProgressInfo.Text = string.Empty;
                    lblRemaining.Text = "...";
                    ETACalculator = new ETACalculator(100, 10);

                    progressBar.ForeColor = Color.Green;
                    progressBar.Value = 0;

                    backgroundWorker.RunWorkerAsync(new { mboxFolder = mboxfolder, outputFolder = outputfolder });
                    btnConvert.Text = "Cancel";
                }
            }
            else
            {
                MessageBox.Show("'Local Mbox Folder' or 'Output Folder' is missing.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        #region BackGroundWorker
        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs eventArgs)
        {
            dynamic settings = eventArgs.Argument;
            string mboxFolder = settings.mboxFolder;
            string outputFolder = settings.outputFolder;

            try
            {
                var sbErrors = new StringBuilder();
                var files = MboxUtils.GetMboxFiles(mboxFolder);

                int idx = 0;
                long totalSize = 0;
                foreach (var file in files)
                {
                    totalSize += new FileInfo(file).Length;
                }

                long lengthRead = 0;
                foreach (var file in files)
                {
                    string directoryName = Path.GetDirectoryName(file);
                    string folderName = directoryName != mboxFolder ? directoryName.Substring(mboxFolder.Length + 1).Replace(".sbd", string.Empty) : Path.GetFileName(file);
                    string outputPath = folderName != null ? Path.Combine(outputFolder, folderName) : outputFolder;

                    var reader = File.OpenText(file);
                    bool firstLine = true;

                    var sb = new StringBuilder();
                    
                    while (!reader.EndOfStream)
                    {
                        if (backgroundWorker.CancellationPending)
                        {
                            eventArgs.Cancel = true;
                            return;
                        }

                        string line = reader.ReadLine(); // reader.ReadLine();

                        if (line != null && ((line.StartsWith("From - ") || reader.EndOfStream) && !firstLine))
                        {
                            string text = sb.ToString();
                            string messageIdx = "MSG_" + idx.ToString("D8");

                            try
                            {
                                MboxUtils.ProcessMessage(outputPath, messageIdx, text);
                            }
                            catch (Exception ex)
                            {
                                string errorMessage = string.Format("{0}.ERROR", messageIdx);
                                sbErrors.AppendLine(string.Format("{0}:{1}", errorMessage, ex));
                                File.WriteAllText(Path.Combine(outputPath, errorMessage), text);
                            }

                            lengthRead += sb.Length;

                            double pct = (100.0 * lengthRead) / totalSize;
                            backgroundWorker.ReportProgress((int)pct, new { file = folderName, lengthRead = lengthRead, totalSize = totalSize, idx = idx });

                            sb.Clear();
                            idx++;
                        }
                        else
                        {
                            sb.AppendLine(line);
                        }

                        firstLine = false;
                    }
                }

                string allErrors = sbErrors.ToString();
                if (!string.IsNullOrEmpty(allErrors))
                {
                    string errorFileName = Path.Combine(outputFolder, "ErrorLog.txt");
                    
                    File.WriteAllText(errorFileName, allErrors);

                    throw new Exception(string.Format("See '{0}' for more details.", errorFileName));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("There was an error during conversion : {0}", ex.Message),
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);

                eventArgs.Cancel = true;
            }
        }

        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // int currentValue = progressBar.Value;
            progressBar.Value = e.ProgressPercentage;

            dynamic info = e.UserState;
            string file = Path.GetFileName(info.file) ?? Path.GetFileName(info.file);
            long lengthRead = info.lengthRead;
            long totalSize = info.totalSize;
            string idx = info.idx.ToString("D8");

            lblProgressInfo.Text = string.Format("Processing file/folder '{0}', message {1}  ({2} from {3}) ({4}%)",
                file,
                idx,
                Utils.StrFormatByteSize(lengthRead),
                Utils.StrFormatByteSize(totalSize),
                e.ProgressPercentage
                );

            ETACalculator.Update((float)lengthRead / (float)totalSize);

            if (ETACalculator.ETAIsAvailable)
            {
                TimeSpan etr = ETACalculator.ETR;
                lblRemaining.Text = string.Format("{0:D2} hrs, {1:D2} mins, {2:D2} secs remaining", etr.Hours, etr.Minutes, etr.Seconds);
            }
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                progressBar.ForeColor = Color.Red;
                progressBar.Value = 0;
                lblProgressInfo.Text = "Cancelled";
            }
            else
            {
                progressBar.ForeColor = Color.Green;
                progressBar.Value = 100;
                lblProgressInfo.Text = "Done (100%)";
            }

            btnConvert.Enabled = true;
            btnConvert.Text = "Convert";

            EndBlock();
        }
        #endregion
    }
}